package com.bsj.media.media;

import bsj.com.faac.def.faacEncConfiguration;
import bsj.com.faac.def.faacEncHandle;
import bsj.com.faac.def.faacOpenOutCfg;
import bsj.com.faac.def.publicDefine;
import bsj.com.faac.faacApi;
import lombok.extern.slf4j.Slf4j;

import java.nio.ByteBuffer;

@Slf4j
public class PcmEncoderAAC2 {

	private faacApi faacApiEnc;
	private faacEncHandle handle;
	private int m_nInputSamples; // 输入样本数
	private int m_nMaxOutputBytes; // 最大输出字节数
	private byte[] OutputBuffer; // 编码输出中转缓冲区

	private int needSampleNum = 0; // 编码一帧aac，需要源音频的样本数,44100*channel*16/8

	// 是否初始化
	private boolean isInit;
	// 时间戳
	private long timestamp;

	public PcmEncoderAAC2() {
		super();
		this.isInit = false;
		this.setTimestamp(0);
	}

	/**
	 * 初始化AAC编码器
	 * 
	 * @param outChannels
	 * @param outSampleRate
	 * @param outBitRate
	 * @return
	 */
	public boolean init(int outChannels, int outSampleRate, int outBitRate, int inChannels, int inSampleRate) {
		faacApiEnc = new faacApi();
		int u32AudioSamplerate = 44100;
		int ucAudioChannel = 1;// 声道数
		faacOpenOutCfg cfg = new faacOpenOutCfg();
		handle = faacApiEnc.faacEncOpen(u32AudioSamplerate, ucAudioChannel, cfg);
		/* get current encoding configuration */
		faacEncConfiguration pConfiguration = faacApiEnc.faacEncGetCurrentConfiguration(handle);
		
		m_nInputSamples = cfg.inputSamples;
		m_nMaxOutputBytes = cfg.maxOutputBytes;
		OutputBuffer = new byte[m_nMaxOutputBytes];
		/* 0 - raw; 1 - ADTS */
		pConfiguration.inputFormat = publicDefine.FAAC_INPUT_16BIT;
		pConfiguration.outputFormat = 0;
		pConfiguration.allowMidside = 1;
		pConfiguration.useTns = 1;// 时域噪音控制,大概就是消爆音
		pConfiguration.aacObjectType = publicDefine.LOW;
		pConfiguration.mpegVersion = publicDefine.MPEG2;

		/* set encoding configuretion */
		faacApiEnc.faacEncSetConfiguration(handle, pConfiguration);

		// 每帧aac需要1024个样本
		needSampleNum = 1024 * outChannels * 2;

		isInit = true;

		return true;
	}

	/**
	 * 输入为PCM数据，输出为AAC数据，返回编码AAC数据长度 并进行重采样
	 * 
	 * @param srcPcm
	 * @param srcLen
	 * @param dst
	 * @param dstOffset
	 * @param dstLen
	 * @return
	 */
	public int Encodec(byte[] srcPcm, int srcOffset, int srcLen, byte[] dst, int dstOffset, int dstLen) {
		if (srcPcm.length < (srcOffset + srcLen)) {
			log.warn("原始data数据长度不对，srcPcm.length:" + srcPcm.length + " srcOffset:" + srcOffset + " srcLen:" + srcLen);
			return 0;
		}

		if (srcLen < m_nInputSamples) {
			log.warn("输入pcm数据长度不够，最小pcm样本数：" + m_nInputSamples + " 当前样本数：" + (srcLen));
			return 0;
		}
		int aacLen = faacApiEnc.faacEncEncodeEx(handle, srcPcm, m_nInputSamples, OutputBuffer, m_nMaxOutputBytes);
		if (aacLen > 0) {
			System.arraycopy(OutputBuffer, 0, dst, dstOffset, aacLen);
		}
		return aacLen;
	}

	/**
	 * 输入为PCM数据，输出为AAC数据，返回编码AAC数据长度
	 * @param srcPcm:
	 * @param srcOffset:
	 * @param srcLen:
	 * @return
	 **/
	public void encodec(byte[] srcPcm, int srcOffset, int srcLen, ByteBuffer aacDatas) {
		if (srcPcm.length < (srcOffset + srcLen)) {
			log.error("原始数据长度不对，srcPcm.length:" + srcPcm.length + " srcOffset:" + srcOffset + " srcLen:" + srcLen);
			return ;
		}

		if (srcLen < m_nInputSamples) {
			log.error("输入pcm数据长度不够，最小pcm样本数：" + m_nInputSamples + " 当前样本数：" + (srcLen));
			return ;
		}
		int aacLen = faacApiEnc.faacEncEncodeEx(handle, srcPcm, m_nInputSamples, OutputBuffer, m_nMaxOutputBytes);
		if (aacLen > 0) {
			aacDatas.putShort((short) aacLen);
			aacDatas.put(OutputBuffer, 0, aacLen);
		}
	}

	public void release() {
	}

	public boolean isInit() {
		return isInit;
	}

	public void setInit(boolean isInit) {
		this.isInit = isInit;
	}

	public long getTimestamp() {
		return timestamp;
	}

	public void setTimestamp(long timestamp) {
		this.timestamp = timestamp;
	}

	// 返回还需要的样本数
	public int getNeedSampleNum() {
		return needSampleNum;
	}

	public void setNeedSampleNum(int needSampleNum) {
		this.needSampleNum = needSampleNum;
	}
}
